@file:OptIn(DelicateCoroutinesApi::class)

package com.kira.solo.schedule.domain

import com.alipay.hulu.shared.CaseExeService
import com.alipay.hulu.shared.io.bean.RecordCaseInfo
import com.alipay.hulu.shared.node.utils.PrepareUtil
import com.kira.solo.schedule.list.FullCaseRepo
import com.kira.solo.schedule.pojo.CasePrepareState
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.channelFlow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import javax.inject.Inject
import javax.inject.Singleton

/**
 * 执行用例
 * @packageName com.kira.solo.schedule.domain
 * @date 2024/1/24 16:52
 * @author zhanglei
 */
@Singleton
class CaseExecutor @Inject constructor(
    private val executor: CaseExeService,
    private val caseRepo: FullCaseRepo,
    private val service: ScheduleTasksService,
) {

    private val exeIds = MutableStateFlow(-1L)

    init {
        GlobalScope.launch(Dispatchers.Main.immediate) {
            exeIds
                .map { taskId ->
                    service.get(taskId).mapNotNull {
                        caseRepo.query(it)
                    }
                }
                .collect { tasks ->
                    tasks.forEach {
                        executor.execute(it)
                        /*prepare(it)
                            .cancellable()
                            .collectLatest { state ->
                                if (state is CasePrepareState.Success) {
                                    executor.execute(it)
                                    cancel()
                                }
                            }*/
                    }
                }

        }
    }

    fun execute(taskId: Long) {
        exeIds.update { taskId }
    }

    /**
     * 检查
     */
    suspend fun prepare(caseInfo: RecordCaseInfo): Flow<CasePrepareState> {
        return channelFlow {
            try {
                val prepareResult = PrepareUtil.doPrepareWork(
                    caseInfo.targetAppPackage
                ) { progress, total, message, _ ->
                    trySend(
                        CasePrepareState.PrepareMsg(
                            progress,
                            total,
                            message
                        )
                    )
                }
                send(if (prepareResult) CasePrepareState.Success else CasePrepareState.Fail)
            } catch (e: Exception) {
                send(CasePrepareState.Error(e))
            }
        }
    }
}